<!DOCTYPE html><html lang="ru" dir="ltr" spellcheck><head><!--#include file="h.htm"--><meta name="description" content="Пиццикато Алексея Лота. Полезные высказывания из книги 'Чистый код' Мартина."><meta name="keywords" content="сайт алексея лота, технологии, мартин, чистый код, алексей лот, сайт лота"><title>Полезные высказывания из книги "Чистый код" Мартина</title></head><body><header><h1 class=m>Пиццикато Алексея Лота</h1><nav><a href="p.htm">Главная</a><a href="m.htm">Песни</a><a href="l.htm">Психология</a><a href="r.htm">Рассказы</a><a href="b.htm">Религия</a><a href="s.htm">Стихотворения</a><a id="i" href="t.htm">Технологии</a><a href="f.htm">Философия</a><a href="i.htm">Фотография</a></nav></header><article id="c"><h2 class=m>Полезные высказывания из книги "Чистый код" Мартина</h2><div id="w">Единственный способ выдержать график - постоянно поддерживать чистоту в коде.<br>Поэтому нужно развивать "чувство кода".<br><br>Чистый код:<br>элегантный и эффективный;<br>логика прямолинейна;<br>зависимости - минимальные;<br>обработка ошибок - полная;<br>производительность - близкая к оптимальной;<br>решает одну задачу;<br>поддерживается в чистоте с течением времени.<br><br>Следующая книга - "Agile software development; Principles, patterns, and practices", 2002.<br><br>Содержательные имена:<br><br>имена всех объектов должны отвечать на все главные вопросы: почему существует, что делает и как используется, не требуют дополнительных комментариев, содержательные, передают намерения программиста;<br>код очевиден, контекст следует из самого кода;<br>не содержат ложных ассоциаций, затемняющих смысл кода;<br>не используются слова со скрытыми значениями, отличными от предполагаемого;<br>лучше обойтись без кодирования типа контейнера в имени.<br><br>Имена не содержат малозаметных различий, непохожи друг на друга излишне.<br><br>Имена не дезинформируют.<br><br>0 не равен O, 1 не равна l.<br><br>Используется правильный шрифт.<br><br>Используются осмысленные различия.<br><br>Имена не дублируют зарезервированные слова с незначительными изменениями.<br><br>Если имена различаются, они должны обозначать разные понятия.<br><br>Различия имен содержательны.<br><br>Префиксы используются, если создают осмысленные различия.<br><br>Не содержат неинформативных, избыточных слов.<br><br>Имена не отличаются только суффиксами.<br><br>Читателю кода понятен смысл различающихся имен - нет соблазна использовать 2 похожих имени по одному назначению.<br><br>Имена удобопроизносимы.<br><br>Программирование - социальная деятельность.<br><br>Не должны состоять из одних сокращений.<br><br>Состоят преимущественно из слов разговорной речи.<br><br>Удобны для поиска.<br><br>Легко находимы в большом объеме кода.<br><br>Относительно редкие.<br><br>Длинные имена лучше коротких.<br><br>Однобуквенные используются только для локальных переменных в коротких методах.<br><br>Длина имени соответствует размеру его области видимости.<br><br>Имя не содержит информации о типе или области видимости.<br><br>Не создает хлопот при расшифровке.<br><br>Не разумно заставлять каждого нового работника изучать очередной "язык" кодирования.<br><br>Имя остается понятным даже в случае опечатки.<br><br>Имя не усложняет изменение типа переменной.<br><br>Типы в именах не кодируются.<br><br>Переменные классов без префиксов.<br><br>Классы и функции компактны - можно обойтись без префиксов.<br><br>Имя не содержит балласта.<br><br>Имена интерфейсов без префиксов.<br><br>Имена не содержат лишней информации.<br><br>Не заставляют мысленно преобразовывать имена в другие.<br><br>Используются имена из пространств задачи и решения.<br><br>Счетчик цикла с малой областьюю видимости можно назвать 1 буквой - это традиция.<br><br>Ясность превыше всего.<br><br>Код понятен для других людей.<br><br>Имена классов и объектов - существительные и их комбинации без глаголов, не содержат обобщенных понятий - Manager, Processor, Data, Info.<br><br>Имена методов - глаголы или глагольные словосочетания.<br><br>Методы чтения или записи и предикаты образуются из значения и префикса get, set и is.<br><br>При перегрузке конструкторов использовать статические методы-фабрики с именами, описывающими аргументы (принудительное инспользование таких методов).<br><br>Нет остроумных шуток.<br><br>Ясность предпочтительнее развлекательной ценности.<br><br>Нет просторечий и сленга.<br><br>Нет шуток.<br><br>Одно слово для каждой концепции.<br><br>Имена функций законченные и логичные.<br><br>Нет эквивалентных методов с именами fetch, retrieve, get в разных классах.<br><br>Нет controller, manager, driver в одной кодовой базе.<br><br>Имена различны принципиально.<br><br>Единый, согласованный лексикон.<br><br>Не используется одно слово в двух смыслах.<br><br>Две разные идеи не обозначены одним термином.<br><br>Нет каламбура.<br><br>Мысли в коде выражаются доступно.<br><br>Используются имена из пространства решения: термины из области информатики, названия алгоритмов, паттернов, математические термины, технические имена.<br><br>Используются имена из пространства задачи (клиентские): если нет подходящего программизма, узнаются у специалиста в предметной области.<br><br>Разделение концепций из пространств задачи и решения.<br><br>Не содержательные сами по себе имена помещаются в определенный контекст для читателя кода - классы, функции и пространства имен с правильно выбранными названиями.<br><br>В крайнем случае контекст уточняется префиксом.<br><br>Контекст не должен вычисляться.<br><br>Функции разделяются на меньшие смысловые фрагменты.<br><br>Нет избыточности контекста.<br><br>Нет работы против собственного инструментария.<br><br>Короткие имена лучше длинных, если только их смысл понятен читателю кода.<br><br>Имена экземпляров более точные.<br><br>Развивать описательные навыки и единый культурный фон.<br><br>Не должно быть опасения возражений при переименовании.<br><br>Функции:<br><br>Первый уровень структуризации.<br><br>Длина не избыточна.<br><br>Не содержит повторяющихся фрагментов кода.<br><br>Один уровень абстракции.<br><br>Функции компактны.<br><br>Функции ещё компактнее.<br><br>Функции желательно не более 20 строк.<br><br>Все функции предельно очевидны.<br><br>Блоки в командах if, else, while и так далее должны состоять из 1 строки, в которой обычно - вызов функции.<br><br>Функции не содержат вложенных структур.<br><br>Не более 1-2 отступов.<br><br>Функция должна выполнять только одну операцию. Она должна выполнять её хорошо. И ничего другого она делать не должна.<br><br>Если функция выполняет только те действия, которые находятся на одом уровне под объявленным именем функции, то эта функция выполняет одну операцию.<br><br>Функции пишутся прежде всего для разложения более крупной концепции (иначе говоря, имени функции) на последовательность действий в следующем уровне абстракции.<br><br>Чтобы определить, что функция выполняет более 1 операции, надо попробовать извлечь из нее другую функцию, которая бы не являлась простой переформулировкой реализации.<br><br>Функцию, выполняющую только одну операцию, невозможно осмысленно разделить на секции.<br><br>Все команды функции неходятся на одном уровне абстракции.<br><br>За каждой функцией должны следовать функции следующего уровня абстракции.<br><br>switch, длинные цепочки if-else скрывать в низкоуровневом классе и не дублировать в коде (использовать полиморфизм).<br><br>Принцип единой ответственности (single responsibility principle).<br><br>Принцип открытости-закрытости (open-closed principle).<br><br>Программа не содержит неограниченного количества других функций с аналогичной структурой (можно использовать абстрактную фабрику).<br><br>Имя точно описывает, что делает функция.<br><br>Длинное имя функции лучше короткого невразумительного.<br><br>Не бойтесь расходовать время на выбор имени функции.<br><br>В именах функций использовать те же словосочетания, глаголы и существительные, что и в модулях.<br><br>В идеальном случае количество аргументов функции равно нулю.<br><br>Использовать функции 1 аргумента:<br>для проверки некоторого условия, связанного с аргументом;<br>для обработки аргумента, его преобразования и возвращения;<br>для события (вход есть, выхода нет);<br>должно быть предельно ясно, что перед читателем событие;<br>остальных форм функций с 1 аргументом лучше избегать;<br>не использовать аргументы-флаги.<br><br>Бинарные функции оправданы, если оба аргумента - упорядоченные компоненты одного значения.<br><br>Использовать все доступные способы для сведения функций к унарной форме.<br><br>Аргументы должны иметь естественную связь и естественный порядок.<br><br>Хорошо подумать перед созданием тернарной функции.<br><br>Упаковывать аргументы в объекты.<br><br>Если переменное количество равноправных аргументов - упаковать в List.<br><br>Хорошее имя функции способно объяснить смысл функции, порядок и смысл ее аргументов.<br><br>В унарных функциях функция и аргумент должны образовывать естественную пару "глагол-существительное".<br><br>Функция не делает чего-то скрытно от пользователя.<br><br>Нет побочных временных привязок функции.<br><br>Нет побочных эффектов.<br><br>Нет причин лишний раз обращаться к сигнатуре функции (нет повторных заходов).<br><br>Выходных аргументов следует избегать.<br><br>Функция может изменять состояние только владельца.<br><br>Функция либо что-то делает (команда), либо отвечает на какой-либо вопрос (запрос).<br><br>Функция либо изменяет состояние объекта, либо возвращает информацию об этом объекте.<br><br>Исключена неоднозначность имен функций.<br><br>Функции-команды не возвращают коды ошибок.<br><br>Вместо возвращения кодов ошибок используются исключения.<br><br>Тела блоков try/catch выделены в отдельные функции.<br><br>Функции выполняют 1 операцию.<br><br>Обработка ошибок - одна операция.<br><br>Нет магнитов зависимостей - классов или перечислений, импортируемых и используемых многими другими классами.<br><br>Нет дублирования алгоритмов.<br><br>Уменьшена вероятность ошибки.<br><br>goto не используется.<br><br>Много return, break, continue допускается в компантных функциях.<br><br>В коде сначала излагаются мысли, а затем "причесываются".<br><br>Система рассматривается как история, которую нужно рассказать.<br><br>Комментарии - неизбежное зло.<br><br>Только код может правдиво сообщить, что он делает.<br><br>Свести использование комментариев к минимуму.<br><br>Комментирование - причина повысить качество кода.<br><br>Вместо юридических комментариев - сссылки на них.<br><br>Информацию лучше передавать в имени функции.<br><br>Использовать комментарии для информации о намерении.<br><br>Комментарии - в случае неудобочитаемых форм данных.<br><br>Комментарии для предупреждения о последствиях.<br><br>Комментарии TODO на будущее.<br><br>Комментарии для подчеркивания важности обстоятельства.<br><br>Не делать комментарии на скорую руку.<br><br>Комментирий не приводит к поиску расшифровки в других модулях.<br><br>Использовать аналог Javadoc.<br><br>Не комментировать бормотанием.<br><br>Не комментировать избыточно.<br><br>Комментарии точнее кода.<br><br>Комментарии точные и соответствуют коду.<br><br>Комментарий не вводит в заблуждение и не дезинформирует.<br><br>Бессмысленные или обязательные комментарии исключены.<br><br>Комментарий не повышает риск обмана и недоразумений.<br><br>Длинные журналы комментариев исключены.<br><br>Комментарии не загромождают и не усложняют код.<br><br>Комментарии-шумы исключены.<br><br>Комментарии не утверждают очевидное, не предоставляя новой информации.<br><br>Комментарии не бесполезны.<br><br>Комментарии не вызывают желания игнорировать их.<br><br>Комментарии не содержат эмоций.<br><br>Комментарии делают работу приятной и эффективной.<br><br>Комментарии не используются там, где можно использовать функцию или переменную.<br><br>Заголовки в комментариях применяются, когда приносят ощутимую пользу.<br><br>Закрывающие скобки не комментируются.<br><br>Ссылки на авторов в комментариях заменяются использованием системы контроля версий.<br><br>Нет закомментированного кода.<br><br>Нет HTML комментариев.<br><br>Комментарии описывают код, к которому отнесены.<br><br>Комментарии не содержат дискуссий, исторических подробностей, не относящихся к делу.<br><br>Связь между комментарием и его кодом очевидна.<br><br>Цель комментария - объяснить код, который не объясняет сам себя.<br><br>Комментарий не нуждается в объяснении.<br><br>Комментарии для API общего пользования не помещаются в коде, не предназначенном для общего потребления.<br><br>Комментарий упрощает понимание алгоритма пользователем.<br><br>Код должен быть хорошо отформатирован.<br><br>Форматирование облегчает передачу информации.<br><br>Маленькие файлы понятнее больших.<br><br>Типичная длина файла 200 строк, предел - 500.<br><br>Исходный файл выглядит как статья.<br><br>Имя файла простое, но содержательное.<br><br>Имени файла достаточно, чтобы определить этот модуль нужен или нет.<br><br>Начальные блоки файла описывают высокоуровневые концепции и алгоритмы.<br><br>Степень детализации увеличивается к концу файла.<br><br>В конце файла собираются все функции и подробности низшего уровня.<br><br>Код читается слева направо и сверху вниз.<br><br>Законченные мысли отделяются пустыми строками.<br><br>Строки кода с тесной связью должны быть сжаты по вертикали.<br><br>Тесно связанные концепции не находятся в разных файлах.<br><br>Следует избегать запущенных переменных.<br><br>Читателю не нужно прыгать туда-сюда по исходным файлам и классам.<br><br>Переменные объявляются максимально близко к месту использования.<br><br>Переменные перечисляются в начале каждой функции.<br><br>Управляющие переменные циклов объявляются внутри конструкции цкила.<br><br>Переменные экземпляров объявляются в начале класса.<br><br>Если одна функция вызывает другую, то они располагаются вблизи друг друга по вертикали.<br><br>Вызывающая функция располагается над вызываемой.<br><br>Концептуально родственные фрагменты кода располагаются близко друг к другу по вертикали.<br><br>Важные концепции излагаются сначала с минимальным количеством второстепенных деталей.<br><br>Строки делать по возможности короткими.<br><br>Пробелы для визуального обозначения приоритета операторов.<br><br>Длинные списки - причина для разделения на классы.<br><br>Горизонтальное выравнивание не применяется.<br><br>Отступы выделяют области видимости.<br><br>Не применяются вырожденные области видимости.<br><br>Группа разработчиков согласует единый стиль форматирования.<br><br>Код продукта оформлен в едином стиле.<br><br>Внешний пользователь не в курсе деталей реализации.<br><br>Методы интерфейса устанавливают политику доступа к данным.<br><br>Классами предоставлены абстрактные интерфейсы, посредством которых пользователь оперирует с сущностью данных.<br><br>Пользователь не имеет представления о фактическом формате данных.<br><br>Объекты скрывают свои данные за абстракциями и предоставвляют функции, работающие с этими данными.<br><br>Структуры данных раскрывают свои данные и не имеют осмысленных функций.<br><br>Процедурный код (код, использующий структуры данных) позволяет легко добавлять новые функции без изменения существующих структур данных.<br><br>ООП-код упрощает добавление новых классов без изменения существующих функций.<br><br>Процедурный код усложняет добавление новых структур данных, так как требуется изменение всех функций.<br><br>ООП-код усложняет добавление новых функций, так как требуется изменение всех классов.<br><br>Данные не обязательно представляются в виде объектов.<br><br>Закон Деметры - модуль не должен знать внутреннее устройство объектов, с которыми работает.<br><br>Метод f класса С должен ограничиваться вызовом методов следующих объектов: С; объекты, созданные f; объекты, переданные f в качестве аргумента; объекты, хранящиеся в переменной экземпляра С.<br><br>Метод не должен вызывать методы объектов, возвращаемых любыми из разрешенных функций.<br><br>Не использовать цепочки вызовов (разделять).<br><br>Не используются гибриды объектов и структур данных.<br><br>Разные уровни детализации не смешиваются.<br><br>Объекты передачи данных - Data transfer object - классы с открытыми переменными без функций используются для преобразования низкоуровневых данных, получаемых из базы, в объекты кода приложения.<br><br>bean - компоненты из приватных переменных, опреации с которыми осуществляются при помощи методов чтения и записи, преимуществ не имеют.<br><br>Активные записи - active records - структуры данных с открытыми переменными, а также с навигационными методами - это структуры данных, и бизнес-логику не содержат.<br><br>Обработка ошибок не заслоняет логику программы.<br><br>Ошибки обрабатываются стильно и элегантно.<br><br>Используются исключения вместо кодов ошибок.<br><br>Начинать с написания команды try-catch-finally для кода, способного вызывать исключение.<br><br>Тип исключения сужается до реально инициируемого.<br><br>Блоки try должны напоминать транзакции.<br><br>Использовать непроверямые исключения.<br><br>С исключениями передавать содержательные сообщения об ошибках.<br><br>Из сведений об исключении должно быть понятно, с какой целью выполнялась операция.<br><br>Классы исключений определены в контексте потребностей вызывающей стороны.<br><br>Инкапсулированы вызовы сторонних API.<br><br>Для обработки особых случаев использовать паттерн особый случай.<br><br>Вместо null выдается исключение или особый случай.<br><br>Для API, возвращающего null - делать обертки.<br><br>Не возвращать null из методов.<br><br>Не передавать null при вызове методов.<br><br>Запрещать передачу null по умолчанию.<br><br>Чистый код должен быть надежным.<br><br>Вместо приведения типа контейнера лучше использовать параметризованные контейнеры.<br><br>Ограничить передачу граничных интерфейсов по платформе (можно инкапсулировать).<br><br>Для стороннего кода писать тесты.<br><br>Сторонний код тестировать в рамках понимания его работы.<br><br>Конструкторы по умолчанию должны иметь конфигурацию.<br><br>Писать учебные тесты, граничные тесты.<br><br>Можно заранее определять интерфейсы, замтем писать паттерн адаптер к готовым.<br><br>Для граничного кода необходимо четкое разделение сторон и тесты, определяющие ожидания пользователя.<br><br>Количество обращений к границам стороннего кода сводится к минимуму.<br><br>Законы TDD:<br>не пишите код продукта, пока не напишете отказной модульный тест;<br>не пишите модульный тест в объеме большем, чем необходимо для отказа (невозможность компиляции является отказом);<br>не пишите код продукта в объеме большем, чем необходимо для прохождения текущего отказного теста.<br><br>Тесты не уступают в качестве коду продукта.<br><br>Тесты развиваются вместе с продуктом.<br><br>Модульные тесты обеспечивают гибкость, удобство сопровождения и возможность повторного использования кода.<br><br>Без тестов любое изменение становится потенциальной ошибкой.<br><br>Некачественные тесты приводят к некачественному коду продукта.<br><br>Чистый тест характеризуется удобочитаемостью: ясностью, простотой и выразительностью.<br><br>В тестах использовать паттерн построение-операции-проверка.<br><br>Тесты не делают ничего лишнего, в них используются только действительно необходимые типы и функции.<br><br>Использовать наборы функций и служебных программ, использующих API.<br><br>Код тестов не такой эффективный как код продукта.<br><br>Чтобы избежать дублирования, можно воспользоваться паттерном шаблонный метод.<br><br>Не более 1 assert в функции теста.<br><br>Одна концепция в тесте (1 тест - 1 проверка).<br><br>Характеристики чистых тестов:<br>тесты должны выполняться быстро;<br>тесты не зависят друг от друга;<br>тесты дают повторяемые результаты в любой среде.<br><br>Результатом выполнения теста должен быть логический признак (результат очевиден).<br><br>Тесты создаются своевременно непосредственно перед кодом продукта.<br><br>Класс должен начинаться со списка переменных.<br>Сначала перечисляются открытые статические константы.<br>Далее следуют приватные статические переменные.<br>За ними идут приватные переменные экземпляров.<br>Затем открытые функции.<br>Приватные вспомогательные функции, вызываемые открытыми функциями, непосредственно за самой открытой функцией (газетная статья).<br><br>Открытые переменные обычно не используют.<br><br>Предпочтительно объявлять переменные и вспомогательные функции приватными.<br><br>Иногда переменную или вспомогательную функцию приходится объявлять защищенной, чтобы иметь возможность обратиться к ней из класса.<br><br>Ослабление инкапсуляции должно быть последней мерой.<br><br>Классы должны быть максимально компактными.<br><br>Компактность класса определяется его ответственностью.<br><br>По имени класса можно определить его размер.<br><br>Краткое описание класса должно укладываться в 25 слов, без выражений "если", "и", "или", "но".<br><br>Принцип единой ответственности: SRP - класс или модуль должен иметь одну - и только одну- причину для изменения (одну ответственность).<br><br>Система должна состоять из множества мелких классов со сформированной структурой.<br><br>Класс взаимодействует с другими классами для реализации желаемого поведения системы.<br><br>Классы должны иметь небольшое количество переменных экземпляров.<br><br>Чем с большим числом переменных работает метод, тем выше связность этого метода со своим классом. Создавать классы с высокой связностью не рекомендуется.<br><br>Высокая связность означает, что методы и переменные класса взаимозависимы.<br><br>Рост числа переменных экземпляров свидетельствует о необходимости выделения класса.<br><br>Рефакторинг может удлинить программу.<br><br>Приватные методы, действие которых распространяется на небольшое подмножество класса - признак возможности усовершенствований.<br><br>Структурирование проводится с учётом изменений.<br><br>Время, необходимое для понимания класса, падает почти до нуля.<br><br>Вероятность того, что одна из функций нарушит работу другой, ничтожно мала.<br><br>Принцип открытости-закрытости: классы должны быть открыты для расширений, но закрыты для модификации.<br><br>Структура системы должна быть такой, чтобы обновление системы создавало как можно меньше проблем.<br><br>В идеале новая функциональность должна реализовываться расширением системы, а не внесением изменений в существующий код.<br><br>С помощью интерфейсов и абстрактных классов класс изолируется от конкретных подробностей.<br><br>Принцип обращения зависимостей: классы системы должы зависеть от абстракций, а не от конкретных подробностей.<br><br>В программных системах фаза инициализации, в которой конструируются объекты приложения и "склеиваются" основные зависимости, должна отделяться от логики времени выполнения, получающей управление после ее завершения.<br><br>Инициализация - область ответственности.<br><br>Код инициализации пишется системно и отделен от логики времени выполнения.<br><br>Удобные идиомы не ведут к нарушению модульности.<br><br>Приложение ничего не знает о main или о процессе конструирования.<br><br>Все аспекты конструирования помещаются в main или в модули, вызываемые из main.<br><br>Если момент создания объекта должен определяться приложением, то использовать паттерн Фабрика.<br><br>Вся информация о конструировании хранится на стороне main.<br><br>Приложение изолировано от подробностей построения.<br><br>Использовать внедрение зависимостей Dependency Injection или обращение контроля Inversion of Control для отделения контруирования от использования.<br><br>Итеративная разработка - сегодня реализуем текущие потребности, а завтра перерабатываеми расширяем систему для реализации новых потребностей.<br><br>Архитектура программных систем может развиваться последовательно, если обеспечить правильное разделение ответственности.<br><br>Компонент-сущность (entity bean) - представление реляционных данных в памяти.<br><br>Применять АОП - модульные конструкции, называемые аспектами, определяют, в каких точках системы поведение должно меняться некоторым последовательным образом в соответствии с потребностями определенной области ответственности (изменения вносит инфраструктура без необходимости вмешательства в целевой код).<br><br>Посредники (proxies) хорошо подходят для простых ситуаций - вызова методов отдельных объектов или классов.<br><br>Использовать POJO-объекты.<br><br>DAO - Data accessor object - объект доступа к данным.<br><br>Использовать aspectJ;<br><br>Не полагаться на BDUF.<br><br>На каждом уровне абстракции архитектура должна оставаться простой и обладать минимальными привязками.<br><br>Хороший API должен исчезать из вида большую часть времени.<br><br>Один человек не может принять все необходимые решения.<br><br>Принятие решений лучше всего откладывать до последнего момента.<br><br>Стандарты применяются разумно, когда они приносят очевидную пользу.<br><br>Главная задача - реализовать интересы клиента.<br><br>Использовать DSL (их код читается как структурированная форма текста, написанного экспертом в данной предметной области).<br><br>Используйте самое простое решение из всех возможных.<br><br>Четыре правила простой архитектуры:<br>архитектура обеспечивает прохождение всех тестов;<br>не содержит дублирующегося кода;<br>выражает намерения программиста;<br>использует минимальное количество классов и методов.<br><br>Система должна делать то, что задумано ее проектировщиком.<br><br>Существует простой способ убедиться в том, что система действительно решает свои задачи.<br><br>Система, тщательно протестированная и прошедшая все тесты, контролируема.<br><br>Обеспечение полной контролируемости системы повышает качество проектирования.<br><br>Для системы необходимо написать тесты и постоянно выполнять их.<br><br>Рефакторинг - последовательная переработка кода.<br><br>Рефакторинг проводится при наличии полного набора тестов.<br><br>В системе не дублируется реализация.<br><br>Применять повторное использованием даже в мелочах.<br><br>Дублирование - главный враг системы.<br><br>Код системы возможно понять без глубокого понимания решаемой проблемы.<br><br>Постараться сделать код выразительным.<br><br>Неравнодушие - драгоценный ресурс.<br><br>Использовать прагматичный подход взамен бессмысленного догматизма.<br><br>Применять нагрузочное тестирование.<br><br>Многопоточность - стратегия устранения привязок.<br><br>Многопоточность - аналогия работы нескольких компьютеров.<br><br>Многопоточность повышает быстродействие не всегда.<br><br>Многопоточность может изменить архитектуру.<br><br>При многопоточности нужно предусмотреть проблемы многопоточной взаимной блокировки, одновременное обновление.<br><br>Многопоточность требует больше производительности и кода.<br><br>Правильная реализация многопоточности сложна.<br><br>Ошибки в многопоточности обычно не воспроизводятся.<br><br>Многопоточность обычно требует фундаментальных изменений в стратегии проектирования.<br><br>Предусмотреть перебивание потоками друг друга (требуется знание обработки байткода и атомарных операций модели памяти).<br><br>Многопоточные архитектуры должны отделяться от основного кода.<br><br>Код реализации многопоточности имеет собственный цикл разработки, модификации и настройки.<br><br>При написании кода многопоточности возникают специфические сложности.<br><br>Предусмотреть обработку обращений к общему объекту.<br><br>Инкапсулировать данные: жестко ограничить доступ и область видимости общих данных.<br><br>Вместо использования общего объекта каждому потоку можно предоставить копию.<br><br>Использовать синхронизацию.<br><br>Потоки должны быть как можно более независимы.<br><br>Постараться разбить данные на независимые подмножества, с которыми могут работать независимые потоки (возможно, на разных процессорах).<br><br>Использовать потоково-безопасные коллекции.<br><br>Использовать неблокирующие решения.<br><br>Изучать доступные классы на предмет потоково-безопасности.<br><br>Модели логического разбиения поведения программы при многопоточности:<br>производители-потребители: потоки-произвоители создают задания и помещают в буфер или очередь. Потоки-потребители извлекают задания из очереди и выполняют их. Производители перед записью дожидаются появления свободного места в очереди, а потребители дожидаются появления заданий в очереди. Производиель записывает задание и сигнализирует о том, что очередь не пуста. Потребитель читает задание и сигнализирует о том, что очередь не заполнена. Обе стороны готовы ждать оповещения о возможности продолжения работы;<br>модель читатели-писатели: писатели пишут в общий ресурс, который считывают читатели. Писатель может блокировать читателей. Нужно найти баланс между потребностями читателей и писателей, чтобы обеспечить правильный режим работы, нормальную производительность и избежать зависания;<br>модель обедающих философов: за круглым столом сидят философы-потоки и думают, в центре - тарелка еды. Каждому философу для еды доступно 2 вилки-ресурсы - по 1 от соседей. Когда философ проголодается - берет вилки, поел - кладет обратно. Сложности проектирования - взаимные блокировки, обратные блокировки, падение производительности и эффективность работы.<br><br>Изучать базовые алгоритмы, разбираться в решениях.<br><br>Избегать использования нескольких методов одного совместно используемого объекта.<br><br>Избегать зависимостей между синхронизированными методами.<br>Или использовать 3 стандартные решения:<br>блокировка на стороне клиента;<br>блокировка на стороне сервера;<br>адаптирующий сервер.<br><br>Код не должен перегружаться лишними синхронизированными объектами, так как блокировки создают задержки и увеличивают затраты ресурсов.<br><br>Синхронизированные секции должны иметь минимальные размеры.<br><br>Корректное завершение не может быть бесконечным ожиданием потока.<br><br>Реализовать логическую изоляцию конфигураций многопоточного кода.<br><br>Протестировать программу с количеством потоков, превышающим число процессоров.<br><br>Применять инструментовку кода для повышения вероятности сбоев.<br><br>Сначала отлаживать основной код.<br><br>Не игнорировать системные ошибки, считая их случайными разовыми сбоями.<br><br>Убедиться, что сам код работает вне многопоточного контекста, созданием POJO- объектов, вызываемых из потоков.<br><br>Реализовать многопоточный код так, чтобы он мог выполняться в различных конфигурациях: с разным числом потоков, тестовых заменителей, времени работы тестов, количеством повторов тестов.<br><br>Найти средства измерения производительсноти системы в разных конфигурациях.<br><br>Реализовать систему так, чтобы количество программных потоков могло легко изменяться, в том числе во время работы системы, в том числе с автоматическим регулированием количества потоков.<br><br>JVM не гарантирует вытесняющей многопоточности.<br><br>Протестировать систему во всех средах, которые могут использоваться для ее развертывания, начиная с ранней стадии.<br><br>Заставить поток исполняться по разным путям в тесте методами object.wait(), object.sleep(), object.yield(), object.priority() - инструментовка кода.<br><br>Автоматическая инструментовка с использованием Aspect-Oriented Framework, CGLIB, ASM, ConTest.<br><br>Суть тестирования - сломать предсказуемость пути выполнения.<br><br>Использовать стратегию случайного выбора пути выполнения для выявления ошибок.<br><br>Типичные источники многопоточных ошибок: работа с общими данными из нескольких потоков, использование пула общих ресурсов.<br><br>Использовать длительное тестирование многопоточного кода перед включением в систему.<br><br>Программирование ближе к ремеслу, чем к науке.<br><br>Спасать положение нужно именно сейчас.<br><br>Во время переработки кода не добавлять в программу новые возможности.<br><br>Предусмотреть, в каких местах будет появляться новый код.<br><br>Множество разных типов со сходными методами - причина выделить класс.<br><br>TDD: не вносить в систему изменения, нарушающие работоспособность системы.<br><br>Добавление теста или класса ничего не нарушит.<br><br>Удалять бесполезные функциии.<br><br>Тесты всегда должны хотя бы запускаться.<br><br>Прочитать Последовательное очищение.<br><br>Переработка кода напоминает кубик Рубика.<br><br>Важный аспект хорошей архитектуры - логическое разбиение кода.<br><br>Плохой код тянет группу ко дну.<br><br>Открытый код требует смелости и доброй воли.<br></div></article><br><footer>&copy;&nbsp;<i>Copyright&nbsp;<a href="https://алексейлот.рф">алексейлот.рф</a>&nbsp;-&nbsp;возьми главную ноту</i></footer></body></html>
